/*
    This file is part of LWX. 

    LWX is the abbreviation of the Light WiMax simulation program which 
    is a ns2 WiMAX network simulation module. LWX allows each user to 
    apply his/her designed scheduling algorithm or other mechanism used 
    in WiMAX network and generate the corresponding simulation results
    for further analysis or other non-commercial purposes.

    Copyright (C) 2008 Yen-Hung Cheng (pplong), NTUST in Taiwan, R.O.C.
    E-Mail: lwx.ns2@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _LWX_BANDWIDTH_SCHEDULER_TCL
#define _LWX_BANDWIDTH_SCHEDULER_TCL

#include "lwx_mac.h"
#include "lwx_wimax_frame.h"

/*
what var you can use for bandwidth allocation

<in lwx_mac.h>

  #define FRAME_PERIOD            0.005
  #define FRAME_SYMBOL            48
  #define DL_PUSC_SUBCH_NUM       60
  #define UL_PUSC_SUBCH_NUM       70
  #define DL_PUSC_SLOT_SYMBOL_NUM 2
  #define UL_PUSC_SLOT_SYMBOL_NUM 2
  
  static vector <LWX_Node> lwx_node_list;
  
what you need to set is
  lwx_node_list.at(i).ctrl.at(j).BWA_Total;
  lwx_node_list.at(i).ctrl.at(j).BWA_FLOW_TYPE;
  lwx_node_list.at(i).ctrl.at(j).BWA_Next_Hop;
*/

class LWX_Bandwidth_Scheduler
{
 
  public:
  void lwx_test_msg(string where, string note)
  {
     cout << "test "<< Scheduler::instance().clock() << " " << where << " " << note << endl;
  }
  
  void lwx_err_msg(string where, string note)
  {
     cout << endl;
     cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl ;
     cout << endl;
     cout << "  your lwx setting gets trouble at " << Scheduler::instance().clock() ;
     cout << ", \n  please check your programe" << endl;
     cout << endl;
     cout << "  error code in:  " << where << endl;
     cout << "  note:  \n         " << note << endl;
     cout << endl;
     cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl ;
     cout << endl;
     exit(1);
  }
  
  void allocate_bandwidth(int bs_node_id, vector <LWX_Node> &lwx_node_list_tmp, LWX_Wimax_Frame &wimax_frame);
};

class LWX_Bandwidth_Scheduler_Test: public LWX_Bandwidth_Scheduler
{
  public:
  void allocate_bandwidth(int bs_node_id, vector <LWX_Node> &lwx_node_list_tmp, LWX_Wimax_Frame &wimax_frame)
  {
      //put your algorithm here
      
  }
};


class LWX_Bandwidth_Scheduler_Round_Robin : public LWX_Bandwidth_Scheduler
{
  public:
  void allocate_bandwidth(int bs_node_id, vector <LWX_Node> &lwx_node_list_tmp, LWX_Wimax_Frame &wimax_frame)
  {
   
    // create pointer to downlink & uplink queue to allocation bandwidth efficiencially
    vector <Flow_Queue*> tmp_ss_to_bs;
    vector <Flow_Queue*> tmp_bs_to_ss;
    
    // get symbol num of DL and UL
    int dl_total_symbol_num = wimax_frame.total_dl_access_zone_bw_unit ();
    int ul_total_symbol_num = wimax_frame.total_dl_access_zone_bw_unit ();
    
    // algorithm calculation var
    int dl_free_symbol_num=0;
    int ul_free_symbol_num=0;
    
    // reset all relative var's value in flow's attribute
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for(unsigned  int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        
        Flow_Queue *tmp_flow_queue = &tmp_node->ctrl_flow.at(j);
        tmp_flow_queue->BWA.clear();
        tmp_flow_queue->BWA_Total=-1;
        tmp_flow_queue->BWA_Total_Byte=-1;
        tmp_flow_queue->BWA_Flow_Type=-1;
        tmp_flow_queue->BWA_Next_Hop=-1;
      }
    }
          
    // collect downlink and flow into corresponding flow queue
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for(unsigned  int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        if(tmp_node->ctrl_flow.at(j).flow_type==FLOW_TYPE_BS_TO_SS) // bs->ss
        {
          tmp_bs_to_ss.push_back(&tmp_node->ctrl_flow.at(j));
        }else if(tmp_node->ctrl_flow.at(j).flow_type==FLOW_TYPE_SS_TO_BS) // ss->bs
        {
          tmp_ss_to_bs.push_back(&tmp_node->ctrl_flow.at(j));
        }else
        {
          lwx_err_msg("in bandwidth allocation", 
             "wrong flow type, this algorithm doesn't support 802.16j");
        }
      }
    }
    
    // test log
    
    for(unsigned int i=0 ;i <tmp_bs_to_ss.size();i++)
    {
     
      ostringstream tmp_pkt_leng;
      tmp_pkt_leng << "dl in " << bs_node_id << " "
                       << "(" << tmp_bs_to_ss.at(i)->flow_type << "/"
                       << tmp_bs_to_ss.at(i)->src_node_id << "/"
                       << tmp_bs_to_ss.at(i)->from_node_id << "/"
                       << tmp_bs_to_ss.at(i)->to_node_id << "/"
                       << tmp_bs_to_ss.at(i)->src_ip << "/"
                       << tmp_bs_to_ss.at(i)->src_port << "/"
                       << tmp_bs_to_ss.at(i)->dst_ip << "/"
                       << tmp_bs_to_ss.at(i)->dst_port << "/"
                       << tmp_bs_to_ss.at(i)->queue_length() << ")" << endl;
      //lwx_test_msg(tmp_pkt_leng.str());
  
    }
  
    for(unsigned int i=0 ;i <tmp_ss_to_bs.size();i++)
    {
     
      ostringstream tmp_pkt_leng;
      tmp_pkt_leng << "up in " << bs_node_id << " "
                       << "(" << tmp_ss_to_bs.at(i)->flow_type << "/"
                       << tmp_ss_to_bs.at(i)->src_node_id << "/"
                       << tmp_ss_to_bs.at(i)->to_node_id << "/"
                       << tmp_ss_to_bs.at(i)->src_ip << "/"
                       << tmp_ss_to_bs.at(i)->src_port << "/"
                       << tmp_ss_to_bs.at(i)->dst_ip << "/"
                       << tmp_ss_to_bs.at(i)->dst_port << "/"
                       << tmp_ss_to_bs.at(i)->queue_length() << ")" << endl;
      //lwx_test_msg(tmp_pkt_leng.str());
  
    }
    
    //
    //  downlink bandwidth allocation
    //
  
  
    // satisfy each dl flow's Rmin
    /*
    dl_free_symbol_num = dl_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      if( tmp_flow_queue->QoS_Class == 1 || tmp_flow_queue->QoS_Class == 2 ||
          tmp_flow_queue->QoS_Class == 3 || tmp_flow_queue->QoS_Class == 4 )
      {
        int allo_symbol = (int)ceil((tmp_flow_queue->Rmin)
                                /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                  * DL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol > dl_free_symbol_num)
        {
          allo_symbol=dl_free_symbol_num; 
        }
        
        tmp_flow_queue->BWA.push_back(allo_symbol);
        tmp_flow_queue->BWA_Total+=allo_symbol;
        
        dl_free_symbol_num -= allo_symbol;
        
        if(dl_free_symbol_num <0)
        {
          lwx_err_msg("RR's DL Rmin", "dl_free_symbol_num <0");
        }
        
      }
    }
    dl_total_symbol_num = dl_free_symbol_num;
    */
    
    // satisfy each dl flow by RR
    dl_free_symbol_num = dl_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                   /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
      allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                   * DL_PUSC_SLOT_SYMBOL_NUM;
      int allo_symbol = (int)ceil ( dl_free_symbol_num / (tmp_bs_to_ss.size()-i));
      allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                               * DL_PUSC_SLOT_SYMBOL_NUM;
        
      if(allo_symbol_max <= allo_symbol + tmp_flow_queue->BWA_Total)
      {
        allo_symbol = allo_symbol_max - tmp_flow_queue->BWA_Total;
      }
      tmp_flow_queue->BWA_Total += allo_symbol;
        
      dl_free_symbol_num -= allo_symbol;
        
      if(dl_free_symbol_num <0)
      {
        lwx_err_msg("RR's DL RR", "dl_free_symbol_num <0");
      }
  
    }
    dl_total_symbol_num = dl_free_symbol_num;
    
  
    // final dl BWA setting
    for(unsigned  int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total 
                                       * tmp_flow_queue->MCR_Avg + tmp_flow_queue->BWA_Backoff) ;
      tmp_flow_queue->BWA_Flow_Type = FLOW_TYPE_BS_TO_SS ;
      
    }
    
    
    // log each phase's bandwidth allocation of each downlink flow
    ostringstream dl_bwa_log;
    dl_bwa_log.clear();
    for(unsigned  int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      dl_bwa_log << tmp_flow_queue->src_ip << "/" 
                 << tmp_flow_queue->src_port << "/" 
                 << tmp_flow_queue->dst_ip << "/"  
                 << tmp_flow_queue->dst_port << " " << endl;
      
      dl_bwa_log << "queue_size: " << tmp_flow_queue->queue_size() << endl;
      
      for(unsigned int j=0; j < tmp_flow_queue->BWA.size(); j++)
      { 
        dl_bwa_log << tmp_flow_queue->BWA.at(j) <<  "/" ;
      }
      dl_bwa_log << tmp_flow_queue->BWA_Total << "\n" ;
    }
    //lwx_test_msg("RR's DL BWA\n", dl_bwa_log.str());
  
  
    //
    //  uplink bandwidth allocation
    //
  
    // satisfy each ul flow's Rmin
    /*
    ul_free_symbol_num = ul_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      if( tmp_flow_queue->QoS_Class == 1 || tmp_flow_queue->QoS_Class == 2 ||
          tmp_flow_queue->QoS_Class == 3 || tmp_flow_queue->QoS_Class == 4 )
      {
        int allo_symbol = (int)ceil((tmp_flow_queue->Rmin)
                                /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                  * UL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol > ul_free_symbol_num)
        {
          allo_symbol=ul_free_symbol_num; 
        }
        
        tmp_flow_queue->BWA.push_back(allo_symbol);
        tmp_flow_queue->BWA_Total+=allo_symbol;
        
        ul_free_symbol_num -= allo_symbol;
        
        if(ul_free_symbol_num <0)
        {
          lwx_err_msg("RR's UL Rmin", "ul_free_symbol_num <0");
        }
        
      }
    }
    ul_total_symbol_num = ul_free_symbol_num;
    */
    
    // satisfy each ul flow by RR
    ul_free_symbol_num = ul_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                   /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
      allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                   * UL_PUSC_SLOT_SYMBOL_NUM;
      int allo_symbol = (int)ceil ( ul_free_symbol_num / (tmp_ss_to_bs.size()-i));
      allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                               * UL_PUSC_SLOT_SYMBOL_NUM;
        
      if(allo_symbol_max <= allo_symbol + tmp_flow_queue->BWA_Total)
      {
        allo_symbol = allo_symbol_max - tmp_flow_queue->BWA_Total;
      }
      tmp_flow_queue->BWA_Total += allo_symbol;
        
      ul_free_symbol_num -= allo_symbol;
        
      if(ul_free_symbol_num <0)
      {
        lwx_err_msg("RR's UL RR", "ul_free_symbol_num <0");
      }
  
    }
    ul_total_symbol_num = ul_free_symbol_num;

    // final ul BWA setting
    for( unsigned int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
  
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total * tmp_flow_queue
                                              ->MCR_Avg + tmp_flow_queue->BWA_Backoff) ;
      tmp_flow_queue->BWA_Flow_Type=FLOW_TYPE_SS_TO_BS;
    }
    
    // log each phase's bandwidth allocation of each uplink flow
    ostringstream ul_bwa_log;
    ul_bwa_log.clear();
    for( unsigned int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      ul_bwa_log << tmp_flow_queue->src_ip << "/" 
                 << tmp_flow_queue->src_port << "/" 
                 << tmp_flow_queue->dst_ip << "/"  
                 << tmp_flow_queue->dst_port << " " << endl;
    
      ul_bwa_log << "queue_size: " << tmp_flow_queue->queue_size() << endl;
                 
      for(unsigned int j=0; j < tmp_flow_queue->BWA.size(); j++)
      { 
        ul_bwa_log << tmp_flow_queue->BWA.at(j) <<  "/" ;
      }
      
      ul_bwa_log << tmp_flow_queue->BWA_Total << "\n" ;
    }
    //lwx_test_msg("RR's UL BWA\n", ul_bwa_log.str());
    
  }
};


class LWX_Bandwidth_Scheduler_Strict_Priority : LWX_Bandwidth_Scheduler
{
  public:
  void allocate_bandwidth(int bs_node_id, vector <LWX_Node> &lwx_node_list_tmp, LWX_Wimax_Frame &wimax_frame)
  {
    
    // create pointer to downlink & uplink queue to allocation bandwidth efficiencially
    vector <Flow_Queue*> tmp_ss_to_bs;
    vector <Flow_Queue*> tmp_bs_to_ss;
    
    // get symbol num of DL and UL
    int dl_total_symbol_num = wimax_frame.total_dl_access_zone_bw_unit ();
    int ul_total_symbol_num = wimax_frame.total_ul_access_zone_bw_unit ();
    
    // algorithm calculation var
    int dl_free_symbol_num=0;
    int ul_free_symbol_num=0;
    
    // reset all relative var's value in flow's attribute
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for(unsigned  int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        
        Flow_Queue *tmp_flow_queue = &tmp_node->ctrl_flow.at(j);
        tmp_flow_queue->BWA.clear();
        tmp_flow_queue->BWA_Total=-1;
        tmp_flow_queue->BWA_Total_Byte=-1;
        tmp_flow_queue->BWA_Flow_Type=-1;
        tmp_flow_queue->BWA_Next_Hop=-1;
      }
    }
    
    // collect downlink and flow into corresponding flow queue
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for( unsigned int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        if(tmp_node->ctrl_flow.at(j).flow_type==FLOW_TYPE_BS_TO_SS) // bs->ss
        {
          tmp_bs_to_ss.push_back(&tmp_node->ctrl_flow.at(j));
        }else if(tmp_node->ctrl_flow.at(j).flow_type==FLOW_TYPE_SS_TO_BS) // ss->bs
        {
          tmp_ss_to_bs.push_back(&tmp_node->ctrl_flow.at(j));
        }else
        {
          lwx_err_msg("in bandwidth allocation", 
             "wrong flow type, this algorithm doesn't support 802.16j");
        }
      }
    }
    
    //
    //  downlink bandwidth allocation
    //
  
    
    // satisfy each dl flow class by class
    // ugs
    dl_free_symbol_num = dl_total_symbol_num;
    for( unsigned int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      if( tmp_flow_queue->QoS_Class == 1 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                     * DL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                      * DL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( dl_free_symbol_num <= allo_symbol)
        {
          allo_symbol = dl_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        dl_free_symbol_num -= allo_symbol;
          
        if(dl_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "dl_free_symbol_num <0");
        }
        
      }
    }
    dl_total_symbol_num = dl_free_symbol_num;
  
    // ert-vr
    dl_free_symbol_num = dl_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      if( tmp_flow_queue->QoS_Class == 2 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                     * DL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                      * DL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( dl_free_symbol_num <= allo_symbol)
        {
          allo_symbol = dl_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        dl_free_symbol_num -= allo_symbol;
          
        if(dl_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "dl_free_symbol_num <0");
        }
        
      }
    }
    dl_total_symbol_num = dl_free_symbol_num;
  
    // rt-vr
    dl_free_symbol_num = dl_total_symbol_num;
    for(unsigned int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      if( tmp_flow_queue->QoS_Class == 3 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                     * DL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                      * DL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( dl_free_symbol_num <= allo_symbol)
        {
          allo_symbol = dl_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        dl_free_symbol_num -= allo_symbol;
          
        if(dl_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "dl_free_symbol_num <0");
        }
        
      }
    }
    dl_total_symbol_num = dl_free_symbol_num;
  
    // nrt-vr
    dl_free_symbol_num = dl_total_symbol_num;
    for( unsigned int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      if( tmp_flow_queue->QoS_Class == 4 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                     * DL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                      * DL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( dl_free_symbol_num <= allo_symbol)
        {
          allo_symbol = dl_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        dl_free_symbol_num -= allo_symbol;
          
        if(dl_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "dl_free_symbol_num <0");
        }
        
      }
    }
    dl_total_symbol_num = dl_free_symbol_num;
  
    // be
    dl_free_symbol_num = dl_total_symbol_num;
    for( unsigned int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      if( tmp_flow_queue->QoS_Class == 5 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                     * DL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                      * DL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( dl_free_symbol_num <= allo_symbol)
        {
          allo_symbol = dl_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        dl_free_symbol_num -= allo_symbol;
          
        if(dl_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "dl_free_symbol_num <0");
        }
        
      }
    }
    dl_total_symbol_num = dl_free_symbol_num;
  
    // final dl BWA setting
    for( unsigned int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total 
                                       * tmp_flow_queue->MCR_Avg + tmp_flow_queue->BWA_Backoff) ;
      tmp_flow_queue->BWA_Flow_Type = FLOW_TYPE_BS_TO_SS ;
      
    }
    
    
    // log each phase's bandwidth allocation of each downlink flow
    ostringstream dl_bwa_log;
    dl_bwa_log.clear();
    for( unsigned int i=0; i <  tmp_bs_to_ss.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_bs_to_ss.at(i);
      
      dl_bwa_log << tmp_flow_queue->src_ip << "/" 
                 << tmp_flow_queue->src_port << "/" 
                 << tmp_flow_queue->dst_ip << "/"  
                 << tmp_flow_queue->dst_port << " " << endl;
      
      dl_bwa_log << "queue_size: " << tmp_flow_queue->queue_size() << endl;
      
      for(unsigned int j=0; j < tmp_flow_queue->BWA.size(); j++)
      { 
        dl_bwa_log << tmp_flow_queue->BWA.at(j) <<  "/" ;
      }
      dl_bwa_log << tmp_flow_queue->BWA_Total << "\n" ;
    }
    //lwx_test_msg("RR's DL BWA\n", dl_bwa_log.str());
  
    //
    //  uplink bandwidth allocation
    //
  
    // satisfy each ul flow class by class
    // ugs
    ul_free_symbol_num = ul_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      if( tmp_flow_queue->QoS_Class == 1 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                     * UL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                      * UL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( ul_free_symbol_num <= allo_symbol)
        {
          allo_symbol = ul_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        ul_free_symbol_num -= allo_symbol;
          
        if(ul_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "ul_free_symbol_num <0");
        }
        
      }
    }
    ul_total_symbol_num = ul_free_symbol_num;
  
    // ert-vr
    ul_free_symbol_num = ul_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      if( tmp_flow_queue->QoS_Class == 2 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                     * UL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                      * UL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( ul_free_symbol_num <= allo_symbol)
        {
          allo_symbol = ul_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        ul_free_symbol_num -= allo_symbol;
          
        if(ul_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "ul_free_symbol_num <0");
        }
        
      }
    }
    ul_total_symbol_num = ul_free_symbol_num;
  
    // rt-vr
    ul_free_symbol_num = ul_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      if( tmp_flow_queue->QoS_Class == 3 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                     * UL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                      * UL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( ul_free_symbol_num <= allo_symbol)
        {
          allo_symbol = ul_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        ul_free_symbol_num -= allo_symbol;
          
        if(ul_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "ul_free_symbol_num <0");
        }
        
      }
    }
    ul_total_symbol_num = ul_free_symbol_num;
  
    // nrt-vr
    ul_free_symbol_num = ul_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      if( tmp_flow_queue->QoS_Class == 4 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                     * UL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                      * UL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( ul_free_symbol_num <= allo_symbol)
        {
          allo_symbol = ul_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        ul_free_symbol_num -= allo_symbol;
          
        if(ul_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "ul_free_symbol_num <0");
        }
        
      }
    }
    ul_total_symbol_num = ul_free_symbol_num;
  
    // be
    ul_free_symbol_num = ul_total_symbol_num;
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      if( tmp_flow_queue->QoS_Class == 5 )
      {
        int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                     /(8*PACKETS_PER_SECOND*tmp_flow_queue->MCR_Avg));
        allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                     * UL_PUSC_SLOT_SYMBOL_NUM;
                                     
        int allo_symbol = (int)ceil (tmp_flow_queue->queue_size()/tmp_flow_queue->MCR_Avg);
        allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                      * UL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol_max <= allo_symbol)
        {
          allo_symbol = allo_symbol_max;
        }
        if( ul_free_symbol_num <= allo_symbol)
        {
          allo_symbol = ul_free_symbol_num;
        }
  
        tmp_flow_queue->BWA_Total = allo_symbol;
          
        ul_free_symbol_num -= allo_symbol;
          
        if(ul_free_symbol_num <0)
        {
          lwx_err_msg("Strict Priority in ugs", "ul_free_symbol_num <0");
        }
      }
    }
    ul_total_symbol_num = ul_free_symbol_num;
  
    // final ul BWA setting
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
  
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total 
                                   * tmp_flow_queue->MCR_Avg + tmp_flow_queue->BWA_Backoff) ;
      tmp_flow_queue->BWA_Flow_Type=FLOW_TYPE_SS_TO_BS;
    }
    
    
    // log each phase's bandwidth allocation of each uplink flow
    ostringstream ul_bwa_log;
    ul_bwa_log.clear();
    for(unsigned  int i=0; i <  tmp_ss_to_bs.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ss_to_bs.at(i);
      
      ul_bwa_log << tmp_flow_queue->src_ip << "/" 
                 << tmp_flow_queue->src_port << "/" 
                 << tmp_flow_queue->dst_ip << "/"  
                 << tmp_flow_queue->dst_port << " " << endl;
    
      ul_bwa_log << "queue_size: " << tmp_flow_queue->queue_size() << endl;
                 
      for(unsigned int j=0; j < tmp_flow_queue->BWA.size(); j++)
      { 
        ul_bwa_log << tmp_flow_queue->BWA.at(j) <<  "/" ;
      }
      
      ul_bwa_log << tmp_flow_queue->BWA_Total << "\n" ;
    }
    //lwx_test_msg("RR's UL BWA\n", ul_bwa_log.str());
    
  }
};


class LWX_Bandwidth_Scheduler_Relay_Sample : LWX_Bandwidth_Scheduler
{
  public:
  void allocate_bandwidth(int bs_node_id, vector <LWX_Node> &lwx_node_list_tmp, LWX_Wimax_Frame &wimax_frame)
  {
    // create pointer to each flow type's queue to allocation bandwidth efficiencially
    vector <Flow_Queue*> tmp_dl_access_flow;
    vector <Flow_Queue*> tmp_dl_relay_flow;
    vector <Flow_Queue*> tmp_ul_access_flow;
    vector <Flow_Queue*> tmp_ul_relay_flow;
    
    // set num of symbol in access and relay zone of dl and ul subframe
    wimax_frame.DL_Access_Zone_Symbol_Num = DL_ACCESS_ZONE_SYMBOL;
    wimax_frame.UL_Access_Zone_Symbol_Num = UL_ACCESS_ZONE_SYMBOL;
    wimax_frame.DL_Relay_Zone_Symbol_Num = DL_RELAY_ZONE_SYMBOL;
    wimax_frame.UL_Relay_Zone_Symbol_Num = UL_RELAY_ZONE_SYMBOL;
    
    // get symbol num of DL and UL
 
    int dl_access_zone_bwa  = wimax_frame.total_dl_access_zone_bw_unit ();
    int dl_relay_zone_bwa   = wimax_frame.total_dl_relay_zone_bw_unit ();
    int ul_access_zone_bwa  = wimax_frame.total_ul_access_zone_bw_unit ();
    int ul_relay_zone_bwa   = wimax_frame.total_ul_relay_zone_bw_unit ();
    
    // algorithm calculation var
    int dl_access_zone_bwa_free=0;
    int dl_relay_zone_bwa_free=0;
    int ul_access_zone_bwa_free=0;
    int ul_relay_zone_bwa_free=0;
  
    
    // reset all relative var's value in flow's attribute
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for(unsigned  int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        
        Flow_Queue *tmp_flow_queue = &tmp_node->ctrl_flow.at(j);
        tmp_flow_queue->BWA.clear();
        tmp_flow_queue->BWA_Total=-1;
        tmp_flow_queue->BWA_MCR=-1;
        tmp_flow_queue->BWA_Total_Byte=-1;
        tmp_flow_queue->BWA_Flow_Type=-1;
        tmp_flow_queue->BWA_Next_Hop=-1;
      }
    }
  
  
  
    // =========================================================
    // path selection:
    //   1.find the path (directly to bs or passing through rs)
    //   2.set BWA_Flow_Type and BWA_Next_Hop
    // =========================================================
    
    // set relay route's access link (second hop) to its own flow_type
    // because this algorithm only for two hop relay and the seconde hop
    // is defaultly set to ss or bs and flow_type is the default flow type
    // e.g. rs->bs or rs->ss_tp
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for(unsigned  int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        Flow_Queue *tmp_flow_queue = &tmp_node->ctrl_flow.at(j);
        switch(tmp_flow_queue->flow_type)
        {
          case FLOW_TYPE_RS_TO_BS:
            tmp_flow_queue->BWA_Flow_Type = tmp_flow_queue->flow_type;
            tmp_flow_queue->BWA_Next_Hop  = tmp_flow_queue->to_node_id;
            tmp_flow_queue->BWA_MCR      = tmp_flow_queue->MCR_Avg;
            break;
          case FLOW_TYPE_RS_TO_SS_TP:
            tmp_flow_queue->BWA_Flow_Type = tmp_flow_queue->flow_type;
            tmp_flow_queue->BWA_Next_Hop  = tmp_flow_queue->to_node_id;
            tmp_flow_queue->BWA_MCR      = tmp_flow_queue->MCR_Avg;
            break;
          default:
            break;
        }
        
      }
    }
    
    // path selection:
    //   # if this flow has relay link, use the first relay link as its next hop
    //   # else use access link
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for(unsigned  int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        Flow_Queue *tmp_flow_queue = &tmp_node->ctrl_flow.at(j);
        if(tmp_flow_queue->flow_type == FLOW_TYPE_BS_TO_SS)
        {
          if(!tmp_flow_queue->relay_link.empty())
          {
            tmp_flow_queue->BWA_Flow_Type = tmp_flow_queue->relay_link.at(0).flow_type;
            tmp_flow_queue->BWA_Next_Hop  = tmp_flow_queue->relay_link.at(0).rs_node_id;
            tmp_flow_queue->BWA_MCR      = tmp_flow_queue->relay_link.at(0).MCR_Avg;
          }
          else
          {
            tmp_flow_queue->BWA_Flow_Type = tmp_flow_queue->flow_type;
            tmp_flow_queue->BWA_Next_Hop  = tmp_flow_queue->to_node_id;
            tmp_flow_queue->BWA_MCR      = tmp_flow_queue->MCR_Avg;
          }
        }
        
        if(tmp_flow_queue->flow_type == FLOW_TYPE_SS_TO_BS)
        {
          if(!tmp_flow_queue->relay_link.empty())
          {
            tmp_flow_queue->BWA_Flow_Type = tmp_flow_queue->relay_link.at(0).flow_type;
            tmp_flow_queue->BWA_Next_Hop  = tmp_flow_queue->relay_link.at(0).rs_node_id;
            tmp_flow_queue->BWA_MCR      = tmp_flow_queue->relay_link.at(0).MCR_Avg;
          }
          else
          {
            tmp_flow_queue->BWA_Flow_Type = tmp_flow_queue->flow_type;
            tmp_flow_queue->BWA_Next_Hop  = tmp_flow_queue->to_node_id;
            tmp_flow_queue->BWA_MCR      = tmp_flow_queue->MCR_Avg;
          }
        }
        
      }
    }
    
    // =========================================================
    // bandwidth allocation:
    //   # access zone: RR + min QoS guarantee
    //   # relay zone:  only RR
    // =========================================================
  
    // collect flow into corresponding flow queue
    
    // !!!!!!! very important design: !!!!!!!!!!!
    //   bs->ss and bs->rs should be scheduling together, because they use same bandwidth
    //   ss->bs_tp and ss->rs should be also scheduling together, because they use same bandwidth
    
    for(unsigned int i=0; i < lwx_node_list_tmp.size(); i++)
    {
      LWX_Node *tmp_node = &lwx_node_list_tmp.at(i);
      for(unsigned  int j=0; j <  tmp_node->ctrl_flow.size(); j++)
      { 
        switch(tmp_node->ctrl_flow.at(j).flow_type)
        {
          case FLOW_TYPE_BS_TO_SS:
          case FLOW_TYPE_BS_TO_RS:
            tmp_dl_access_flow.push_back(&tmp_node->ctrl_flow.at(j));
            break;
          case FLOW_TYPE_SS_TO_BS:
          case FLOW_TYPE_SS_TO_RS_TP:
            tmp_ul_access_flow.push_back(&tmp_node->ctrl_flow.at(j));
            break;
          case FLOW_TYPE_RS_TO_BS:
            tmp_ul_relay_flow.push_back(&tmp_node->ctrl_flow.at(j));
            break;
          case FLOW_TYPE_RS_TO_SS_TP:
            tmp_dl_relay_flow.push_back(&tmp_node->ctrl_flow.at(j));
            break; 
          default:
            lwx_err_msg("in bandwidth allocation", 
               "wrong flow type, this algorithm doesn't support 802.16j non-transparent RS");
        }
        
      }
    }
    
  
    //
    //  downlink access bandwidth allocation
    //
  
  
    // satisfy each dl flow's Rmin
    dl_access_zone_bwa_free = dl_access_zone_bwa;
    for(unsigned  int i=0; i <  tmp_dl_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_dl_access_flow.at(i);
      
      if( tmp_flow_queue->QoS_Class == 1 || tmp_flow_queue->QoS_Class == 2 ||
          tmp_flow_queue->QoS_Class == 3 || tmp_flow_queue->QoS_Class == 4 )
      {
        int allo_symbol = (int)ceil((tmp_flow_queue->Rmin)
                                /(8*PACKETS_PER_SECOND*tmp_flow_queue->BWA_MCR));
        allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                  * DL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol > dl_access_zone_bwa_free)
        {
          allo_symbol=dl_access_zone_bwa_free; 
        }
        
        tmp_flow_queue->BWA.push_back(allo_symbol);
        tmp_flow_queue->BWA_Total+=allo_symbol;
        
        dl_access_zone_bwa_free -= allo_symbol;
        
        if(dl_access_zone_bwa_free <0)
        {
          lwx_err_msg("RR's DL Rmin", "dl_free_symbol_num <0");
        }
        
      }
    }
    dl_access_zone_bwa = dl_access_zone_bwa_free;
    
    
    // satisfy each dl flow by RR
    dl_access_zone_bwa_free = dl_access_zone_bwa;
    for( unsigned int i=0; i <  tmp_dl_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_dl_access_flow.at(i);
      
      int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                   /(8*PACKETS_PER_SECOND*tmp_flow_queue->BWA_MCR));
      allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                   * DL_PUSC_SLOT_SYMBOL_NUM;
      int allo_symbol = (int)ceil ( dl_access_zone_bwa_free / (tmp_dl_access_flow.size()-i));
      allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                               * DL_PUSC_SLOT_SYMBOL_NUM;
        
      if(allo_symbol_max <= allo_symbol + tmp_flow_queue->BWA_Total)
      {
        allo_symbol = allo_symbol_max - tmp_flow_queue->BWA_Total;
      }
      tmp_flow_queue->BWA_Total += allo_symbol;
        
      dl_access_zone_bwa_free -= allo_symbol;
        
      if(dl_access_zone_bwa_free <0)
      {
        lwx_err_msg("RR's DL RR", "dl_access_zone_bwa_free <0");
      }
  
    }
    dl_access_zone_bwa = dl_access_zone_bwa_free;
    
  
    // final dl BWA setting
    for(unsigned  int i=0; i <  tmp_dl_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_dl_access_flow.at(i);
      
      
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total 
                                       * tmp_flow_queue->BWA_MCR+ tmp_flow_queue->BWA_Backoff) ;
    }
    
    
    // log each phase's bandwidth allocation of each downlink flow
    ostringstream dl_access_bwa_log;
    dl_access_bwa_log << "============ dl access bwa log: ============" << endl;
    dl_access_bwa_log << "{(src_node_id/from_node_id/to_node_id) (src_ip/src_port/dst_port)\n"
                      << " (flow_type/MCR_Avg) qsize (queue_size) \n"
                      << "BWA: (Total/Total_Byte/Flow_type/Next_Hop/MCR_Avg)} \n";
    
    for( unsigned int i=0; i <  tmp_dl_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_dl_access_flow.at(i);
      
      dl_access_bwa_log << "{("
                        << tmp_flow_queue->src_node_id << "/" 
                        << tmp_flow_queue->from_node_id << "/" 
                        << tmp_flow_queue->to_node_id << "/"  
                        << tmp_flow_queue->dst_port << ") " ;
      
      dl_access_bwa_log << "(" << tmp_flow_queue->src_ip << "/" 
                        << tmp_flow_queue->src_port << "/" 
                        << tmp_flow_queue->dst_ip << "/"  
                        << tmp_flow_queue->dst_port << ") ";
                        
      dl_access_bwa_log << "(" << tmp_flow_queue->flow_type << "/" 
                        << tmp_flow_queue->MCR_Avg << ") ";
      
      dl_access_bwa_log << "qsize (" << tmp_flow_queue->queue_size() << ") " ;
      
      dl_access_bwa_log << "BWA: (" 
                        << tmp_flow_queue->BWA_Total << "/" 
                        << tmp_flow_queue->BWA_Total_Byte << "/" 
                        << tmp_flow_queue->BWA_Flow_Type << "/" 
                        << tmp_flow_queue->BWA_Next_Hop << "/" 
                        << tmp_flow_queue->BWA_MCR << ")} " ;
                        
    }
    //lwx_test_msg("RR's DL ACCESS BWA\n", dl_access_bwa_log.str());
  
    //
    //  downlink relay bandwidth allocation (rs->ss)
    //
  
    
    // satisfy each dl relay flow by RR
    dl_relay_zone_bwa_free = dl_relay_zone_bwa;
    for(unsigned  int i=0; i <  tmp_dl_relay_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_dl_relay_flow.at(i);
      
      int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                   /(8*PACKETS_PER_SECOND*tmp_flow_queue->BWA_MCR));
      allo_symbol_max     = (int)ceil ( allo_symbol_max/ DL_PUSC_SLOT_SYMBOL_NUM) 
                                   * DL_PUSC_SLOT_SYMBOL_NUM;
      int allo_symbol = (int)ceil ( dl_relay_zone_bwa_free / (tmp_dl_relay_flow.size()-i));
      allo_symbol     = (int)ceil ( allo_symbol/ DL_PUSC_SLOT_SYMBOL_NUM) 
                               * DL_PUSC_SLOT_SYMBOL_NUM;
        
      if(allo_symbol_max <= allo_symbol + tmp_flow_queue->BWA_Total)
      {
        allo_symbol = allo_symbol_max - tmp_flow_queue->BWA_Total;
      }
      tmp_flow_queue->BWA_Total += allo_symbol;
        
      dl_relay_zone_bwa_free -= allo_symbol;
        
      if(dl_relay_zone_bwa_free <0)
      {
        lwx_err_msg("RR's DL Relay RR", "dl_relay_zone_bwa_free <0");
      }
  
    }
    dl_relay_zone_bwa = dl_relay_zone_bwa_free;
    
  
    // final dl BWA setting
    for(unsigned  int i=0; i <  tmp_dl_relay_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_dl_relay_flow.at(i);
      
      
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total 
                                       * tmp_flow_queue->BWA_MCR + tmp_flow_queue->BWA_Backoff) ;
      
    }
    
    // log each phase's bandwidth allocation of each downlink relay flow
    ostringstream dl_relay_bwa_log;
    dl_relay_bwa_log << "============ dl relay bwa log: ============" << endl;
    dl_relay_bwa_log << "{(src_node_id/from_node_id/to_node_id) (src_ip/src_port/dst_port)\n"
                      << " (flow_type/MCR_Avg) qsize (queue_size) \n"
                      << "BWA: (Total/Total_Byte/Flow_type/Next_Hop/MCR_Avg)} \n";
    
    for(unsigned  int i=0; i <  tmp_dl_relay_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_dl_relay_flow.at(i);
      
      dl_relay_bwa_log  << "{("
                        << tmp_flow_queue->src_node_id << "/" 
                        << tmp_flow_queue->from_node_id << "/" 
                        << tmp_flow_queue->to_node_id << "/"  
                        << tmp_flow_queue->dst_port << ") " ;
      
      dl_relay_bwa_log  << "(" << tmp_flow_queue->src_ip << "/" 
                        << tmp_flow_queue->src_port << "/" 
                        << tmp_flow_queue->dst_ip << "/"  
                        << tmp_flow_queue->dst_port << ") ";
                        
      dl_relay_bwa_log  << "(" << tmp_flow_queue->flow_type << "/" 
                        << tmp_flow_queue->MCR_Avg << ") ";
      
      dl_relay_bwa_log << "qsize (" << tmp_flow_queue->queue_size() << ") " ;
      
      dl_relay_bwa_log << "BWA: (" 
                        << tmp_flow_queue->BWA_Total << "/" 
                        << tmp_flow_queue->BWA_Total_Byte << "/" 
                        << tmp_flow_queue->BWA_Flow_Type << "/" 
                        << tmp_flow_queue->BWA_Next_Hop << "/" 
                        << tmp_flow_queue->BWA_MCR << ")} " ;
                        
    }
    //lwx_test_msg("RR's DL RELAY BWA\n", dl_relay_bwa_log.str());
  
  
    //
    //  uplink access bandwidth allocation
    //
  
  
    // satisfy each ul flow's Rmin
    ul_access_zone_bwa_free = ul_access_zone_bwa;
    for(unsigned  int i=0; i <  tmp_ul_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ul_access_flow.at(i);
      
      if( tmp_flow_queue->QoS_Class == 1 || tmp_flow_queue->QoS_Class == 2 ||
          tmp_flow_queue->QoS_Class == 3 || tmp_flow_queue->QoS_Class == 4 )
      {
        int allo_symbol = (int)ceil((tmp_flow_queue->Rmin)
                                /(8*PACKETS_PER_SECOND*tmp_flow_queue->BWA_MCR));
        allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                  * UL_PUSC_SLOT_SYMBOL_NUM;
        
        if(allo_symbol > ul_access_zone_bwa_free)
        {
          allo_symbol=ul_access_zone_bwa_free; 
        }
        
        tmp_flow_queue->BWA.push_back(allo_symbol);
        tmp_flow_queue->BWA_Total+=allo_symbol;
        
        ul_access_zone_bwa_free -= allo_symbol;
        
        if(ul_access_zone_bwa_free <0)
        {
          lwx_err_msg("RR's UL Rmin", "ul_free_symbol_num <0");
        }
        
      }
    }
    ul_access_zone_bwa = ul_access_zone_bwa_free;
    
    
    // satisfy each ul flow by RR
    ul_access_zone_bwa_free = ul_access_zone_bwa;
    for(unsigned  int i=0; i <  tmp_ul_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ul_access_flow.at(i);
      
      int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                   /(8*PACKETS_PER_SECOND*tmp_flow_queue->BWA_MCR));
      allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                   * UL_PUSC_SLOT_SYMBOL_NUM;
      int allo_symbol = (int)ceil ( ul_access_zone_bwa_free / (tmp_ul_access_flow.size()-i));
      allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                               * UL_PUSC_SLOT_SYMBOL_NUM;
        
      if(allo_symbol_max <= allo_symbol + tmp_flow_queue->BWA_Total)
      {
        allo_symbol = allo_symbol_max - tmp_flow_queue->BWA_Total;
      }
      tmp_flow_queue->BWA_Total += allo_symbol;
        
      ul_access_zone_bwa_free -= allo_symbol;
        
      if(ul_access_zone_bwa_free <0)
      {
        lwx_err_msg("RR's UL RR", "ul_access_zone_bwa_free <0");
      }
  
    }
    ul_access_zone_bwa = ul_access_zone_bwa_free;
    
  
    // final ul BWA setting
    for(unsigned  int i=0; i <  tmp_ul_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ul_access_flow.at(i);
      
      
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total 
                                       * tmp_flow_queue->BWA_MCR + tmp_flow_queue->BWA_Backoff) ;
      
    }
    
    
    // log each phase's bandwidth allocation of each downlink flow
    ostringstream ul_access_bwa_log;
    ul_access_bwa_log << "============ ul access bwa log: ============" << endl;
    ul_access_bwa_log << "{(src_node_id/from_node_id/to_node_id) (src_ip/src_port/dst_port)\n"
                      << " (flow_type/MCR_Avg) qsize (queue_size) \n"
                      << "BWA: (Total/Total_Byte/Flow_type/Next_Hop/MCR_Avg)} \n";
    
    for(unsigned  int i=0; i <  tmp_ul_access_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ul_access_flow.at(i);
      
      ul_access_bwa_log << "{("
                        << tmp_flow_queue->src_node_id << "/" 
                        << tmp_flow_queue->from_node_id << "/" 
                        << tmp_flow_queue->to_node_id << "/"  
                        << tmp_flow_queue->dst_port << ") " ;
      
      ul_access_bwa_log << "(" << tmp_flow_queue->src_ip << "/" 
                        << tmp_flow_queue->src_port << "/" 
                        << tmp_flow_queue->dst_ip << "/"  
                        << tmp_flow_queue->dst_port << ") ";
                        
      ul_access_bwa_log << "(" << tmp_flow_queue->flow_type << "/" 
                        << tmp_flow_queue->MCR_Avg << ") ";
      
      ul_access_bwa_log << "qsize (" << tmp_flow_queue->queue_size() << ") " ;
      
      ul_access_bwa_log << "BWA: (" 
                        << tmp_flow_queue->BWA_Total << "/" 
                        << tmp_flow_queue->BWA_Total_Byte << "/" 
                        << tmp_flow_queue->BWA_Flow_Type << "/" 
                        << tmp_flow_queue->BWA_Next_Hop << "/" 
                        << tmp_flow_queue->BWA_MCR << ")} " ;
                        
    }
    //lwx_test_msg("RR's UL ACCESS BWA\n", ul_access_bwa_log.str());
  
    //
    //  uplink relay bandwidth allocation (rs->ss)
    //
  
    
    // satisfy each ul relay flow by RR
    ul_relay_zone_bwa_free = ul_relay_zone_bwa;
    for(unsigned  int i=0; i <  tmp_ul_relay_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ul_relay_flow.at(i);
      
      int allo_symbol_max = (int)floor((tmp_flow_queue->Rmax)
                                   /(8*PACKETS_PER_SECOND*tmp_flow_queue->BWA_MCR));
      allo_symbol_max     = (int)ceil ( allo_symbol_max/ UL_PUSC_SLOT_SYMBOL_NUM) 
                                   * UL_PUSC_SLOT_SYMBOL_NUM;
      int allo_symbol = (int)ceil ( ul_relay_zone_bwa_free / (tmp_ul_relay_flow.size()-i));
      allo_symbol     = (int)ceil ( allo_symbol/ UL_PUSC_SLOT_SYMBOL_NUM) 
                               * UL_PUSC_SLOT_SYMBOL_NUM;
        
      if(allo_symbol_max <= allo_symbol + tmp_flow_queue->BWA_Total)
      {
        allo_symbol = allo_symbol_max - tmp_flow_queue->BWA_Total;
      }
      tmp_flow_queue->BWA_Total += allo_symbol;
        
      ul_relay_zone_bwa_free -= allo_symbol;
        
      if(ul_relay_zone_bwa_free <0)
      {
        lwx_err_msg("RR's UL Relay RR", "ul_relay_zone_bwa_free <0");
      }
  
    }
    ul_relay_zone_bwa = ul_relay_zone_bwa_free;
    
  
    // final ul BWA setting
    for( unsigned int i=0; i <  tmp_ul_relay_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ul_relay_flow.at(i);
      
      
      tmp_flow_queue->BWA_Total_Byte = (int)(tmp_flow_queue->BWA_Total 
                                       * tmp_flow_queue->BWA_MCR + tmp_flow_queue->BWA_Backoff) ;
      
    }
    
    // log each phase's bandwidth allocation of each downlink relay flow
    ostringstream ul_relay_bwa_log;
    ul_relay_bwa_log << "============ ul relay bwa log: ============" << endl;
    ul_relay_bwa_log << "{(src_node_id/from_node_id/to_node_id) (src_ip/src_port/dst_port)\n"
                      << " (flow_type/MCR_Avg) qsize (queue_size) \n"
                      << "BWA: (Total/Total_Byte/Flow_type/Next_Hop/MCR_Avg)} \n";
    
    for(unsigned  int i=0; i <  tmp_ul_relay_flow.size(); i++)
    { 
      Flow_Queue *tmp_flow_queue = tmp_ul_relay_flow.at(i);
      
      ul_relay_bwa_log  << "{("
                        << tmp_flow_queue->src_node_id << "/" 
                        << tmp_flow_queue->from_node_id << "/" 
                        << tmp_flow_queue->to_node_id << "/"  
                        << tmp_flow_queue->dst_port << ") " ;
      
      ul_relay_bwa_log  << "(" << tmp_flow_queue->src_ip << "/" 
                        << tmp_flow_queue->src_port << "/" 
                        << tmp_flow_queue->dst_ip << "/"  
                        << tmp_flow_queue->dst_port << ") ";
                        
      ul_relay_bwa_log  << "(" << tmp_flow_queue->flow_type << "/" 
                        << tmp_flow_queue->MCR_Avg << ") ";
      
      ul_relay_bwa_log << "qsize (" << tmp_flow_queue->queue_size() << ") " ;
      
      ul_relay_bwa_log << "BWA: (" 
                        << tmp_flow_queue->BWA_Total << "/" 
                        << tmp_flow_queue->BWA_Total_Byte << "/" 
                        << tmp_flow_queue->BWA_Flow_Type << "/" 
                        << tmp_flow_queue->BWA_Next_Hop << "/" 
                        << tmp_flow_queue->BWA_MCR << ")} " ;
                        
    }
    //lwx_test_msg("RR's UL RELAY BWA\n", ul_relay_bwa_log.str());
  
  
  }  
};


#endif
